import Cesium, { Cartesian3, GeometryInstance, GroundPrimitive, Rectangle } from '../Ces/Cesium'
import Config from '../Core/Config';

class DetectiveLineLayer {
  private _primitives

  constructor() {
    this.create(Config.DetectiveLineOptions);
  }

  create(options: any): void {
    const DetectiveLines = options.line;
    const primitives: any[] = [];

    Object.keys(DetectiveLines).forEach((element) => {
      const color1 = DetectiveLines[element].color;
      const color = Cesium.Color.fromCssColorString(color1);
      const positions: Cartesian3[] = [];
      const linePositions = DetectiveLines[element].positions;

      for (let i = 0; i < linePositions.length; i++) {
        const longitude = linePositions[i][1];
        const latitude = linePositions[i][0];
        const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0.0);
        positions.push(position);
      }

      const instance = new Cesium.GeometryInstance({
        geometry: new Cesium.GroundPolylineGeometry({
          positions,
          width: options.width??2.0
        }),
      });

      const polylinePrimitive = new Cesium.GroundPolylinePrimitive({
        geometryInstances: instance,
        asynchronous: true,
      });

      polylinePrimitive.appearance = new Cesium.PolylineMaterialAppearance({
        material: Cesium.Material.fromType(Cesium.Material.PolylineOutlineType),
      });
      polylinePrimitive.appearance.material.uniforms.color = color;
      polylinePrimitive.appearance.material.uniforms.outlineColor = color;
      polylinePrimitive.appearance.material.uniforms.outlineWidth = 2.0;
      primitives.push(polylinePrimitive);

      const xmax = linePositions[0][1];
      const xmin = xmax - 1.0;
      const ymax = linePositions[0][0];
      const ymin = linePositions[1][0];
      const rectangle1 = Cesium.Rectangle.fromDegrees(
        xmin,
        Math.min(ymin, ymax),
        xmax,
        Math.max(ymin, ymax)
      );

      primitives.push(
        DetectiveLineLayer.createText(
          rectangle1,
          element.substr(1, element.length - 1),
          color1
        )
      );
    });

    this._primitives = primitives;
  }

  private static drawTextCanvas(text: string, style: string): HTMLCanvasElement {
    const canvas = document.createElement('canvas');
    canvas.width = 100;
    canvas.height = 600;
    const ctx = canvas.getContext('2d')!;

    ctx.font = '80px 楷体';
    ctx.fillStyle = style;
    ctx.textAlign = 'center';
    const str = text;
    const offsetX = 40;
    let offsetY = 80;

    for (let i = 0; i < str.length; i++) {
      ctx.fillText(str[i], offsetX, offsetY);
      offsetY += 80;
    }

    return canvas;
  }

  private static createText(
    rectangle: Rectangle,
    text: string,
    style: string
  ) {
    const geometry = new Cesium.RectangleGeometry({
      rectangle,
    });
    const geometryInstances: GeometryInstance[] = [];

    geometryInstances.push(
      new Cesium.GeometryInstance({
        geometry,
      })
    );

    const options: any = {
      geometryInstances,
      appearance: new Cesium.MaterialAppearance({
        renderState: {
          depthTest: { enabled: true },
          depthMask: true,
          blending: Cesium.BlendingState.ALPHA_BLEND,
          cull: {
            enabled: false,
            face: Cesium.CullFace.FRONT,
          },
        },
        translucent: false,
      }),
      asynchronous: true,
    };

    const image = DetectiveLineLayer.drawTextCanvas(text, style);

    const primitive = new Cesium.GroundPrimitive(options);

    primitive.appearance.material = new Cesium.Material({
      fabric: {
        type: 'Image',
        uniforms: {
          image,
        },
      },
    });

    return primitive;
  }

  destroy(): void {
    if (Cesium.defined(this._primitives)) {
      this._primitives.forEach((primitive) => {
        primitive.destroy();
      });
      this._primitives = undefined;
    }

    return Cesium.destroyObject(this);
  }

  isDestroyed(): boolean {
    return false;
  }

  update(frameState): void {
    if (frameState.passes.render && Cesium.defined(this._primitives)) {
      for (let i = 0; i < this._primitives.length; i++) {
        this._primitives[i].update(frameState);
      }
    }
  }
}

export default DetectiveLineLayer;
